package co.edu.uniandes.sd.mundo;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;

public class SolicitadorDeCertificados 
{
	public final static String EXPEDIR_CERTIFICADO = "EXPEDIR_CERTIFICADO";
	
	private ObjectOutputStream salida;
	private ObjectInputStream entrada;
	private X509Certificate mensaje;
	private String servidorChat;
	private Socket cliente;
	private PrivateKey llavePrivada;
	private PublicKey llavePublica;
	
	public SolicitadorDeCertificados(String login, String pass, PrivateKey llavePrivada, PublicKey llavePublica)
	{
		this.llavePrivada = llavePrivada;
		this.llavePublica = llavePublica;
		servidorChat = "127.0.0.1";
		ejecutarCliente(login, pass);
	}
	
	// conectarse al servidor y procesar mensajes del servidor
	   private void ejecutarCliente(String login, String pass) 
	   {
	      // conectarse al servidor, obtener flujos, procesar la conexión
	      try {
	         conectarAServidor(); // Paso 1: crear un socket para realizar la conexión
	         obtenerFlujos();      // Paso 2: obtener los flujos de entrada y salida
	         enviarDatos(EXPEDIR_CERTIFICADO+";"+login+";"+pass);
	         enviarDatos(llavePrivada);
	         enviarDatos(llavePublica);
	         procesarConexion(); // Paso 3: procesar la conexión
	      }

	      // el servidor cerró la conexión
	      catch ( EOFException excepcionEOF ) {
	         System.err.println( "El cliente termino la conexión" );
	      }

	      // procesar los problemas que pueden ocurrir al comunicarse con el servidor
	      catch ( IOException excepcionES ) {
	         excepcionES.printStackTrace();
	      }

	      finally {
	         cerrarConexion(); // Paso 4: cerrar la conexión
	      }

	   } // fin del método ejecutarCliente

	   // conectarse al servidor
	   private void conectarAServidor() throws IOException
	   {      
	      mostrarMensaje( "Intentando realizar conexión\n" );

	      // crear Socket para realizar la conexión con el servidor
	      cliente = new Socket( InetAddress.getByName( servidorChat ), 12345 );

	      // mostrar la información de la conexión
	      mostrarMensaje( "Conectado a: " + 
	         cliente.getInetAddress().getHostName() );
	   }

	   // obtener flujos para enviar y recibir datos
	   private void obtenerFlujos() throws IOException
	   {
	      // establecer flujo de salida para los objetos
	      salida = new ObjectOutputStream( cliente.getOutputStream() );      
	      salida.flush(); // vacíar búfer de salida para enviar información de encabezado

	      // establecer flujo de entrada para los objetos
	      entrada = new ObjectInputStream( cliente.getInputStream() );

	      mostrarMensaje( "\nSe recibieron los flujos de E/S\n" );
	   }

	   // procesar la conexión con el servidor
	   private void procesarConexion() throws IOException
	   {

	       // procesar mensajes enviados del servidor

	         // leer mensaje y mostrarlo en pantalla
	         try {
	            mensaje = ( X509Certificate ) entrada.readObject();
	            mostrarMensaje( "\n" + mensaje );
	         }

	         // atrapar los problemas que pueden ocurrir al leer del servidor
	         catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
	            mostrarMensaje( "\nSe recibió un objeto de tipo desconocido" );
	         }

	   } // fin del método procesarConexion

	   // cerrar flujos y socket
	   private void cerrarConexion() 
	   {
	      mostrarMensaje( "\nCerrando conexión" );
	      
	      try {
	         salida.close();
	         entrada.close();
	         cliente.close();
	      }
	      catch( IOException excepcionES ) {
	         excepcionES.printStackTrace();
	      }
	   }

	   // enviar mensaje al servidor
	   private void enviarDatos( Object mensaje )
	   {
	      // enviar objeto al servidor
	      try {
	         salida.writeObject( mensaje );
	         salida.flush();
	         mostrarMensaje( "\nCLIENTE>>> " + mensaje );
	      }

	      // procesar los problemas que pueden ocurrir al enviar el objeto
	      catch ( IOException excepcionES ) {
	         
	      }
	   }

	   // método utilitario que es llamado desde otros subprocesos para manipular a 
	   // areaPantalla en el subproceso despachador de eventos
	   private void mostrarMensaje( String mensajeAMostrar )
	   {
	      System.out.println(mensajeAMostrar);
	   }

	   public X509Certificate darCertificado()
	   {
		   return mensaje;
	   }	   
}
